package edu.cmu.cs.webapp.ioms.views;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;

import edu.cmu.cs.webapp.ioms.dao.DataAccessException;
import edu.cmu.cs.webapp.ioms.dao.impl.OrderDAOImpl;
import edu.cmu.cs.webapp.ioms.dao.impl.ProductDAOImpl;
import edu.cmu.cs.webapp.ioms.logging.Alerts;
import edu.cmu.cs.webapp.ioms.models.Ingredient;
import edu.cmu.cs.webapp.ioms.models.Product;
import edu.cmu.cs.webapp.ioms.models.PurchaseOrder;
import edu.cmu.cs.webapp.ioms.test.DummieDataGenerator;
import edu.cmu.cs.webapp.ioms.ui.providers.ingredient.IngredientInforTableViewerLabelProvider;
import edu.cmu.cs.webapp.ioms.ui.providers.order.OrdersTableViewerContentProvider;
import edu.cmu.cs.webapp.ioms.ui.providers.order.OrdersTableViewerLabelProvider;
import edu.cmu.cs.webapp.ioms.ui.providers.product.ProductListTableViewerContentProvider;
import edu.cmu.cs.webapp.ioms.ui.providers.product.ProductListTableViewerLableProvider;
import edu.cmu.cs.webapp.ioms.utils.IOMSUtils;
import edu.cmu.cs.webapp.ioms.utils.SWTUtils;


public class ProductView extends ViewPart implements ISelectionProvider {
	public static final String ID_VIEW = "edu.cmu.cs.webapp.ioms.views.prodcut";
	private TableViewer _viewer;
	private Combo _searchCombo;
	private Text _keywordSearch;
	private Table _table;
	private ITableLabelProvider labelProvider;
	private ProductFilter viewerFilter;

	public static int PRODUCT_ID = 0;
	public static int PRODUCT_NAME = 1;
	public static int PRODUCT_PRICE = 2;
	public static int PRODUCT_DESCRIPTION = 3;

	private Product[] products;

	public void init(IViewSite site) throws PartInitException {
		super.init(site);
		site.setSelectionProvider(this);
	}

	public ProductView() {
		viewerFilter = new ProductFilter();
		labelProvider = new ProductListTableViewerLableProvider();
	}

	public void createPartControl(Composite parent) {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		gridLayout.marginHeight = 2;
		gridLayout.marginWidth = 2;

		// set the parent's layout
		parent.setLayout(gridLayout);

		Composite composite = new Composite(parent, SWT.NONE);
		GridData gridCompositeData = new GridData();
		gridCompositeData.verticalAlignment = GridData.BEGINNING;
		gridCompositeData.horizontalAlignment = GridData.FILL;
		gridCompositeData.grabExcessHorizontalSpace = true;

		composite.setLayoutData(gridCompositeData);

		GridLayout gridCompositeGroupLayout = new GridLayout();

		// this is to set the number of columns
		gridCompositeGroupLayout.numColumns = 3;
		composite.setLayout(gridCompositeGroupLayout);

		Label searchLabel = new Label(composite, SWT.NONE);
		searchLabel.setText("Search under:");

		// the second part of the column, previous label takes one seat
		_searchCombo = SWTUtils.createCombo(composite, new String[] {
				"Product ID", "Prodcut Name", "Product Price",
				"Product Description" }, 1);
		_searchCombo.select(0);

		_keywordSearch = new Text(composite, SWT.BORDER);
		GridData txtGridData = new GridData(GridData.FILL_HORIZONTAL);
		txtGridData.horizontalAlignment = SWT.FILL;
		txtGridData.grabExcessHorizontalSpace = true;
		_keywordSearch.setLayoutData(txtGridData);
		_keywordSearch.addModifyListener(new ModifyListener() {
			@Override
			public void modifyText(ModifyEvent event) {
				Text text = (Text) event.widget;
				viewerFilter.setText(text.getText());
				_viewer.refresh();
			}
		});

		createTableViewer(parent);
	}

	private void createTableViewer(Composite parent) {

		GridData gridData = new GridData();
		gridData.horizontalSpan = 3;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		gridData.verticalAlignment = GridData.FILL;

		// here is to specify that its parent is parent;
		_table = new Table(parent, SWT.FULL_SELECTION | SWT.BORDER
				| SWT.H_SCROLL | SWT.V_SCROLL);
		_table.setLayoutData(gridData);

		_table.setHeaderVisible(true);
		_table.setLinesVisible(true);

		// product id
		TableColumn idColumn = new TableColumn(_table, SWT.NONE);
		idColumn.setText("#");
		idColumn.setWidth(60);
		idColumn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				_viewer.setSorter(new IngredientSorter(
						IngredientInforTableViewerLabelProvider.INGREDIENT_INVENTORY,
						sortDirection == SWT.DOWN));
			}
		});

		// product name
		TableColumn nameColumn = new TableColumn(_table, SWT.NONE);
		nameColumn.setText("Product Name");
		nameColumn.setWidth(100);
		nameColumn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				_viewer.setSorter(new IngredientSorter(
						ProductListTableViewerLableProvider.PRODCUT_NAME,
						sortDirection == SWT.DOWN));
			}
		});

		// product price
		TableColumn priceColumn = new TableColumn(_table, SWT.NONE);
		priceColumn.setText("Price");
		priceColumn.setWidth(100);
		priceColumn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				_viewer.setSorter(new IngredientSorter(
						ProductListTableViewerLableProvider.PRODUCT_PRICE,
						sortDirection == SWT.DOWN));
			}
		});

		// product description
		TableColumn descColumn = new TableColumn(_table, SWT.NONE);
		descColumn.setText("Description");
		descColumn.setWidth(275);
		descColumn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				_viewer
						.setSorter(new IngredientSorter(
								ProductListTableViewerLableProvider.PRODUCT_DESCRIPTION,
								sortDirection == SWT.DOWN));
			}
		});

		_viewer = new TableViewer(_table);
		_viewer.setUseHashlookup(true);
		_viewer.addFilter(viewerFilter);

		_viewer.setLabelProvider(labelProvider);
		_viewer.setContentProvider(new ProductListTableViewerContentProvider());

		refreshProductsView();

	}

	public static int updateSortDirection(TableColumn column) {
		Table table = column.getParent();
		if (column == table.getSortColumn()) {
			if (table.getSortDirection() == SWT.UP) {
				table.setSortDirection(SWT.DOWN);
			} else {
				table.setSortDirection(SWT.UP);
			}
		} else {
			table.setSortColumn(column);
			table.setSortDirection(SWT.DOWN);
		}
		return table.getSortDirection();
	}

	/*
	 * @SuppressWarnings("unchecked") private static void sort(final TableViewer
	 * viewer, final int property, final boolean ascending) {
	 * 
	 * DummieDataGenerator input = (DummieDataGenerator) viewer.getInput();
	 * Object[] objs = input.getProducts(); ArrayList productList = new
	 * ArrayList<Product>(); for (Object obj : objs){ // if (obj instanceof
	 * Product){ Product obj1 = (Product)obj; productList.add((Product)obj1); //
	 * } } // Collections.sort(productList, new ProductComparator(property,
	 * ascending)); viewer.setInput((List)productList); viewer.refresh();
	 * 
	 * // viewer.refresh();
	 * 
	 * Collections.sort(input, new ProductComparator (property, ascending));
	 * viewer.refresh(); if ((viewer.getControl().getStyle() & SWT.VIRTUAL) !=
	 * 0) { List input = (List) viewer.getInput(); Collections.sort(input, new
	 * ProductComparator(property, ascending)); viewer.refresh(); } else {
	 * viewer.setComparator(new ProductComparator(property, ascending)); } }
	 */

	/*
	 * private static final class ProductComparator extends ViewerComparator
	 * implements Comparator { private final boolean ascending; private final
	 * int property; public ProductComparator( final int property, final boolean
	 * ascending ) { this.property = property; this.ascending = ascending; }
	 * public int compare( final Viewer viewer, final Object object1, final
	 * Object object2 ) { return compare( object1, object2 ); } public int
	 * compare( final Object object1, final Object object2 ) { Product product1
	 * = ( Product )object1; Product product2 = ( Product )object2; int result =
	 * 0; if( property == PRODUCT_ID ) { result = ((new
	 * Integer(product1.getProd_id())).compareTo(new
	 * Integer(product2.getProd_id())));
	 * 
	 * } else if( property == PRODUCT_NAME ) { result =
	 * product1.getProd_name().compareTo(product2.getProd_name()); } else if(
	 * property == PRODUCT_PRICE ) { result =
	 * String.valueOf(product1.getPrice())
	 * .compareTo(String.valueOf(product2.getPrice())); } else if( property ==
	 * PRODUCT_DESCRIPTION ) { result =
	 * product1.getProd_description().compareTo(product2.getProd_description());
	 * } if( !ascending ) { result = result * -1; } return result; } }
	 */

	private class IngredientSorter extends ViewerSorter {
		private int columnIndex;
		private final boolean ascending;

		public IngredientSorter(int criteria, boolean ascending) {
			super();
//			specify which coloumn needs to be compared
			this.columnIndex = criteria;
			this.ascending = ascending;
		}

		@SuppressWarnings("unchecked")
		@Override
		public int compare(Viewer viewer, Object e1, Object e2) {
			int result = 0;
			if (e1 instanceof Ingredient && e2 instanceof Ingredient) {
				result = getComparator().compare(
						labelProvider.getColumnText(e1, columnIndex),
						labelProvider.getColumnText(e2, columnIndex));
			}

			if (!ascending) {
				result = result * -1;
			}
			return result;
		}
	}

	public void refreshProductsView() {
		// this._viewer.setInput(new DummieDataGenerator());
		UIJob refreshJob = new RefreshJob("Refresh");
		refreshJob.setUser(true);
		refreshJob.schedule();
	}

	private class RefreshJob extends UIJob {

		public RefreshJob(String name) {
			super(name);
		}

		@Override
		public IStatus runInUIThread(IProgressMonitor monitor) {
			monitor.beginTask("Refreshing Orders List...",
					IProgressMonitor.UNKNOWN);
			try {

				List<Product> list = new ProductDAOImpl().getAllProd();
				products = new Product[list.size()];
				int i = 0;

				// manually parse the value to the list
				for (Product p : list) {
					if (p != null) {
						products[i] = p;
						i++;
					}
				}

				/*
				 * orders = new OrderDAOImpl().getAllOrder().toArray( new
				 * PurchaseOrder[0]); for reference
				 */
			} catch (DataAccessException e) {
				Alerts.getInstance().detailError("Data Access Error",
						e.getLocalizedMessage(), e);
				return Status.CANCEL_STATUS;
			}

			if (products != null) {
				_viewer.setInput(products);
			}

			monitor.done();

			return Status.OK_STATUS;
		}
	}

	public final class ProductFilter extends ViewerFilter {
		private String text;

		public void setText(final String s) {
			this.text = s;
		}

		public boolean select(final Viewer viewer, final Object parentElement,
				final Object element) {
			boolean result = true;
			if (text != null && text.length() > 0) {
				String txt = labelProvider.getColumnText(element, _searchCombo
						.getSelectionIndex());
				result = txt.toLowerCase().indexOf(text.toLowerCase()) != -1;
			}
			return result;
		}

		public boolean isFilterProperty(final Object element, final String prop) {
			return true;
		}
	}

	@Override
	public void setFocus() {
		// TODO Auto-generated method stub

	}

	public void selectionChanged(SelectionChangedEvent event) {
		// TODO Auto-generated method stub

	}

	@Override
	public void addSelectionChangedListener(ISelectionChangedListener listener) {
		this._viewer.addSelectionChangedListener(listener);
	}

	@Override
	public ISelection getSelection() {

		if (_viewer != null)
			return _viewer.getSelection();
		return null;
	}

	@Override
	public void removeSelectionChangedListener(
			ISelectionChangedListener listener) {
		this._viewer.removeSelectionChangedListener(listener);

	}

	@Override
	public void setSelection(ISelection selection) {
		if (_viewer != null) {
			_viewer.setSelection(selection);
		}
	}

	/**
	 * 
	 * @param site
	 * @return
	 */
	public static ProductView getProductsListViewPart(IViewSite site) {

		// return the current view that is deployed in the workbench, then any
		// other composite can called on this method to get the current view
		IViewPart view = site.getPage().findView(ProductView.ID_VIEW);
		if (view instanceof ProductView) {
			return ((ProductView) view);
		}
		return null;
	}

}
